package com.sudo.service.admin.runnable;

import com.sudo.common.enums.ExceptionLimit;
import com.sudo.common.enums.RunModeType;
import com.sudo.common.enums.ThrowOrReturn;
import com.sudo.common.task.TaskUtil;
import com.sudo.common.utils.ThreadLocalUtil;
import com.sudo.dao.admin.entity.SysMethodJob;
import com.sudo.dao.admin.entity.SysServerNodeJob;
import com.sudo.starter.log.constant.LogConstant;
import com.sudo.rpc.api.common.RpcConstant;
import com.sudo.rpc.api.model.CallTask;
import com.sudo.rpc.api.service.RmiSetServerService;
import com.sudo.service.admin.exception.RunnableException;
import com.sudo.service.admin.service.SysMethodJobService;
import com.sudo.service.admin.service.SysServerNodeJobService;
import com.sudo.service.tldata.ThreadLocalObject;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
 * @Author：DayDayUp
 * @Create：2023/4/18 17:06
 */
@Component
public class NextJobUtil {

    private static SysMethodJobService sysMethodJobService;
    private static SysServerNodeJobService sysServerNodeJobService;
    private static RmiSetServerService rmiSetServerService;
    private static AsyncTaskExecutor asyncTaskExecutor;

    @Autowired
    public NextJobUtil(SysMethodJobService sysMethodJobService,
                       SysServerNodeJobService sysServerNodeJobService,
                       RmiSetServerService rmiSetServerService,
                       AsyncTaskExecutor asyncTaskExecutor){
        NextJobUtil.sysMethodJobService = sysMethodJobService;
        NextJobUtil.sysServerNodeJobService = sysServerNodeJobService;
        NextJobUtil.rmiSetServerService = rmiSetServerService;
        NextJobUtil.asyncTaskExecutor = asyncTaskExecutor;
    }

    /**
     * 执行currentJobId下的子任务
     * @param currentJobId 当前任务ID
     * @param throwOrReturn 父任务异常或正常
     */
    public static void runNextMethodJobs(int currentJobId, ThrowOrReturn throwOrReturn) {
        SysMethodJob sysMethodJob = sysMethodJobService.querySysMethodJobById(currentJobId);
        if (StringUtils.isBlank(sysMethodJob.getNextJobIds())) {
            return;
        }
        if (throwOrReturn.name().equals(ThrowOrReturn.THROW.name())) {
            if (ExceptionLimit.EX_STOP.name().equals(sysMethodJob.getNextJobLimit())) {
                return;
            }
        }
        String[] jobIdArr = StringUtils.split(sysMethodJob.getNextJobIds(), ",");
        for (String jobIdStr : jobIdArr) {
            if (StringUtils.isBlank(jobIdStr)) {
                continue;
            }
            int jobId = Integer.parseInt(jobIdStr.trim());
            if (RunModeType.SYNC.name().equals(sysMethodJob.getNextJobMode())) {
                SysMethodJob syncMethodJob = sysMethodJobService.querySysMethodJobById(jobId);
                try {
                    if (syncMethodJob != null) {
                        Map<String, Object> jobConfigMap = ThreadLocalObject.initJobConfigMap(syncMethodJob);
                        ThreadLocalUtil.setTlMap(jobConfigMap);
                        TaskUtil.callTaskMethod(syncMethodJob.getBeanName(),syncMethodJob.getMethodName(),syncMethodJob.getMethodParams());
                    }
                } catch (Exception e) {
                    throw new RunnableException("子线程运行异常，子任务："+syncMethodJob.getId());
                }
            } else if (RunModeType.ASYNC.name().equals(sysMethodJob.getNextJobMode())) {
                String traceId = MDC.get(LogConstant.TRACE_ID);
                asyncTaskExecutor.execute(()->{
                    MDC.put(LogConstant.PARENT_TRACE_ID, traceId);
                    MDC.put(LogConstant.TRACE_ID,traceId+"."+jobIdStr);
                    SysMethodJob asyncMethodJob = sysMethodJobService.querySysMethodJobById(jobId);
                    try {
                        if (asyncMethodJob != null){
                            Map<String, Object> jobConfigMap = ThreadLocalObject.initJobConfigMap(asyncMethodJob);
                            ThreadLocalUtil.setTlMap(jobConfigMap);
                            TaskUtil.callTaskMethod(asyncMethodJob.getBeanName(),asyncMethodJob.getMethodName(),asyncMethodJob.getMethodParams());
                        }
                    } catch (Exception e) {
                        throw new RunnableException("子线程运行异常，子任务："+asyncMethodJob.getId());
                    }
                });
            }

        }
    }

    /**
     * 执行currentJobId下的子任务
     * @param currentJobId 当前任务ID
     * @param status 父任务异常或正常
     */
    public static void runNextRpcJobs(int currentJobId, int status) {
        SysServerNodeJob sysServerNodeJob = sysServerNodeJobService.querySysServerNodeJobById(currentJobId);
        if (StringUtils.isBlank(sysServerNodeJob.getNextJobIds())) {
            return;
        }
        if (status == RpcConstant.exceptionCode) {
            if (ExceptionLimit.EX_STOP.name().equals(sysServerNodeJob.getNextJobLimit())) {
                return;
            }
        }
        String[] jobIdArr = StringUtils.split(sysServerNodeJob.getNextJobIds(), ",");
        for (String jobIdStr : jobIdArr) {
            if (StringUtils.isBlank(jobIdStr)) {
                continue;
            }
            int jobId = Integer.parseInt(jobIdStr.trim());
            if (RunModeType.SYNC.name().equals(sysServerNodeJob.getNextJobMode())) {
                SysServerNodeJob syncServerNodeJob = sysServerNodeJobService.querySysServerNodeJobById(jobId);
                try {
                    if (syncServerNodeJob != null) {
                        Map<String, Object> jobConfigMap = ThreadLocalObject.initJobConfigMap(syncServerNodeJob);
                        ThreadLocalUtil.setTlMap(jobConfigMap);
                        String[] split = syncServerNodeJob.getServer().split(":");
                        CallTask callTask = new CallTask(split[0], Integer.parseInt(split[1]),
                                syncServerNodeJob.getBeanName(), syncServerNodeJob.getMethodName()
                                ,syncServerNodeJob.getMethodParams(),syncServerNodeJob.getCallbackFun(),MDC.get(LogConstant.TRACE_ID));
                        rmiSetServerService.callServer(callTask);
                    }
                } catch (Exception e) {
                    throw new RunnableException("子线程运行异常，子任务："+syncServerNodeJob.getId());
                }
            } else if (RunModeType.ASYNC.name().equals(sysServerNodeJob.getNextJobMode())) {
                String traceId = MDC.get(LogConstant.TRACE_ID);
                asyncTaskExecutor.execute(()->{
                    MDC.put(LogConstant.PARENT_TRACE_ID, traceId);
                    MDC.put(LogConstant.TRACE_ID,traceId+"."+jobIdStr);
                    SysServerNodeJob asyncServerNodeJob = sysServerNodeJobService.querySysServerNodeJobById(jobId);
                    try {
                        if (asyncServerNodeJob != null){
                            Map<String, Object> jobConfigMap = ThreadLocalObject.initJobConfigMap(asyncServerNodeJob);
                            ThreadLocalUtil.setTlMap(jobConfigMap);
                            String[] split = asyncServerNodeJob.getServer().split(":");
                            CallTask callTask = new CallTask(split[0], Integer.parseInt(split[1]),
                                    asyncServerNodeJob.getBeanName(), asyncServerNodeJob.getMethodName()
                                    ,asyncServerNodeJob.getMethodParams(),asyncServerNodeJob.getCallbackFun(),MDC.get(LogConstant.TRACE_ID));
                            rmiSetServerService.callServer(callTask);
                        }
                    } catch (Exception e) {
                        throw new RunnableException("子线程运行异常，子任务："+asyncServerNodeJob.getId());
                    }
                });
            }

        }
    }
}
